/**
 * @file pwm.c
 * @author leijiapeng (email:leijiapeng123@163.com)
 * @brief
 * @version 0.1
 * @date 2025-09-18
 *
 * @copyright Copyright (c) 2025
 *
 */

#include "pwm.h"
#include "stm32f1xx_hal.h"
#include <stdint.h>
#include "log.h"

uint8_t PWM_Init(PWM_Instance *pwm, TIM_HandleTypeDef *htim, TIM_Channel channel, uint32_t tclk, float period,
                 uint8_t dutyratio)
{
    if (pwm == NULL || htim == NULL)
    {
        Log_Error("PWM_Init failed, the parameter pwm or htim is NULL");
        return 0; // 参数错误
    }

    // 验证其他参数
    if (tclk == 0 || period < 0.0f)
    {
        Log_Error("PWM_Init failed, the parameter tclk is 0 or period < 0");
        return 0;
    }

    // 验证通道是否有效
    if (channel != CHANNEL_1 && channel != CHANNEL_2 && channel != CHANNEL_3 && channel != CHANNEL_4)
    {
        Log_Error("PWM_Init failed, the parameter channel is out of range");
        return 0; // 无效的通道
    }

    pwm->htim    = htim;
    pwm->channel = channel;
    pwm->tclk    = tclk;

    if (!PWM_SetPeriod(pwm, period) || !PWM_SetDutyRatio(pwm, dutyratio))
    {
        return 0; // 设置周期或占空比失败
    }

    return 1; // 成功
}

uint8_t PWM_SetPeriod(PWM_Instance *pwm, float period)
{
    if (pwm == NULL)
    {
        Log_Error("PWM_SetPeriod failed, the parameter pwm is NULL");
        return 0; // 参数错误
    }
    if (period < 0.0)
    {
        Log_Error("PWM_SetPeriod failed, the parameter period < 0");
        period = 0.0f;
    }

    pwm->period = period;

    // 避免整数溢出，先进行除法再乘法
    float    freq       = pwm->tclk / (float)(pwm->htim->Init.Prescaler + 1);
    uint32_t autoreload = (uint32_t)(period * freq);

    // 检查计算结果是否在有效范围内
    if (autoreload > 0xFFFF)
    {
        Log_Warn("PWM_SetPeriod warning, the parameter period is too large, set to max value");
        autoreload = 0xFFFF; // 限制在最大值
    }

    __HAL_TIM_SET_AUTORELOAD(pwm->htim, autoreload);
    return 1; // 成功
}

uint8_t PWM_SetDutyRatio(PWM_Instance *pwm, uint8_t dutyratio)
{
    if (pwm == NULL)
    {
        Log_Error("PWM_SetDutyRatio failed, the parameter pwm is NULL");
        return 0; // 参数错误
    }
    if (dutyratio > 100)
    {
        Log_Warn("PWM_SetDutyRatio warning, the parameter dutyratio > 100, set to 100");
        dutyratio = 100;
    }
    pwm->dutyratio = dutyratio;

    uint32_t compare_value = (uint32_t)((dutyratio * pwm->htim->Instance->ARR) / 100);
    __HAL_TIM_SET_COMPARE(pwm->htim, pwm->channel, compare_value);
    return 1; // 成功
}

/* 只是对HAL的函数进行了形式上的封装 */
void PWM_Start(PWM_Instance *pwm)
{
    if (pwm == NULL || pwm->htim == NULL)
    {
        Log_Error("PWM_Start failed, the parameter pwm or pwm->htim is NULL");
        return;
    }
    HAL_TIM_PWM_Start(pwm->htim, pwm->channel);
}

/* 只是对HAL的函数进行了形式上的封装 */
void PWM_Stop(PWM_Instance *pwm)
{
    if (pwm == NULL || pwm->htim == NULL)
    {
        Log_Error("PWM_Stop failed, the parameter pwm or pwm->htim is NULL");
        return;
    }
    HAL_TIM_PWM_Stop(pwm->htim, pwm->channel);
}
